home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume21 / filterfile < prev    next >
Encoding:
Internet Message Format  |  1990-02-05  |  18.6 KB

  1. Subject:  v21i002:  Apply a filter to a file, safely
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: Dan Bernstein <brnstnd@stealth.acf.nyu.edu>
  7. Posting-number: Volume 21, Issue 2
  8. Archive-name: filterfile
  9.  
  10. [  Everyone probably has one of these in their toolkit, although not
  11.    with such extensive copyright, warranty and version numbers; at
  12.    any rate, it's worth having an archived one.  /r$  ]
  13.  
  14. filterfile applies a filter to a file, writing the result to another
  15. file.  Various options let filterfile delete the input file, set the times
  16. of the output to the times of the input, or set the protection mode of the
  17. output to that of the input.
  18.  
  19.  
  20. #! /bin/sh
  21. # This is a shell archive.  Remove anything before this line, then unpack
  22. # it by saving it into a file and typing "sh file".  To overwrite existing
  23. # files, type "sh file -c".  You can also feed this as standard input via
  24. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  25. # will see the following message at the end:
  26. #        "End of shell archive."
  27. # Contents:  README CHANGES filterfile.man filterfile.c Makefile
  28. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  29. if test -f 'README' -a "${1}" != "-c" ; then 
  30.   echo shar: Will not clobber existing file \"'README'\"
  31. else
  32. echo shar: Extracting \"'README'\" \(738 characters\)
  33. sed "s/^X//" >'README' <<'END_OF_FILE'
  34. Xfilterfile - apply a filter to a file
  35. X
  36. Xfilterfile version 1.201, October 28, 1989.
  37. XCopyright (c) 1989, Daniel J. Bernstein.
  38. XAll rights reserved.
  39. X
  40. XThis distribution packaged October 28, 1989.
  41. X
  42. XFiles:
  43. XCHANGES         Description of changes since first distributed version
  44. XREADME          This document
  45. XMakefile        Installation commands
  46. Xfilterfile.c    The program
  47. Xfilterfile.man  Documentation
  48. X
  49. XEdit the options in Makefile and type make. filterfile will be the
  50. Xexecutable program; filterfile.1 will be the nroff'ed manual.
  51. X
  52. XI don't pretend to know your machine's setup so there's no make install.
  53. X
  54. XRead CHANGES for a list of changes. Type filterfile -C and filterfile -W
  55. Xfor copyright and warranty information, filterfile -H for help.
  56. END_OF_FILE
  57. if test 738 -ne `wc -c <'README'`; then
  58.     echo shar: \"'README'\" unpacked with wrong size!
  59. fi
  60. # end of 'README'
  61. fi
  62. if test -f 'CHANGES' -a "${1}" != "-c" ; then 
  63.   echo shar: Will not clobber existing file \"'CHANGES'\"
  64. else
  65. echo shar: Extracting \"'CHANGES'\" \(312 characters\)
  66. sed "s/^X//" >'CHANGES' <<'END_OF_FILE'
  67. XVersion 1.201, 10/28/89.
  68. X
  69. XChanged filefilter to filterfile at one spot in manual (whoops!).
  70. XPut missing \n into an error message.
  71. XPut in new copyright notice and warranty.
  72. X
  73. XVersion 1.2.
  74. X
  75. XMinor changes.
  76. XAdded filenames into most of the errors.
  77. XMade execve into execvp, so filterfile searches paths.
  78. X
  79. XVersion 1.0.
  80. END_OF_FILE
  81. if test 312 -ne `wc -c <'CHANGES'`; then
  82.     echo shar: \"'CHANGES'\" unpacked with wrong size!
  83. fi
  84. # end of 'CHANGES'
  85. fi
  86. if test -f 'filterfile.man' -a "${1}" != "-c" ; then 
  87.   echo shar: Will not clobber existing file \"'filterfile.man'\"
  88. else
  89. echo shar: Extracting \"'filterfile.man'\" \(4968 characters\)
  90. sed "s/^X//" >'filterfile.man' <<'END_OF_FILE'
  91. X.TH filterfile 1
  92. X.SH NAME
  93. Xfilterfile \- apply a filter to a file
  94. X.SH SYNTAX
  95. Xfilterfile
  96. X[
  97. X\fB\-dDpPtT\fI
  98. X] [
  99. X\fB\-o\fIout
  100. X] [
  101. X\fB\-e\fIext
  102. X] [
  103. X\fB\-ACHUVW\fI
  104. X]
  105. Xfile /path/filter
  106. X[
  107. Xarg ...
  108. X]
  109. X.SH DESCRIPTION
  110. X\fIfilterfile\fB
  111. Xapplies a filter to a file,
  112. Xwriting the result to another file.
  113. XVarious options let
  114. X\fIfilterfile\fB
  115. Xdelete the input file,
  116. Xset the times of the output to the times of the input,
  117. Xor set the protection mode of the output to that of the input.
  118. X.PP
  119. XOptions
  120. X.B ACHUVW
  121. Xprint the authorship notice,
  122. Xcopyright notice,
  123. Xhelp notice,
  124. Xshort usage summary,
  125. Xversion number,
  126. Xand warranty information respectively.
  127. X.PP
  128. X\fIfilterfile\fB
  129. Xhas several flags:
  130. X.TP 12
  131. X.B -d
  132. XDelete the input file after the filter runs successfully.
  133. XThe input file will remain untouched if the filter crashes
  134. Xor exits with an error indication.
  135. X.TP
  136. X.B -D
  137. XDo not delete the input file. This is the default.
  138. X.TP
  139. X.B -p
  140. XSet the protection modes of the output to the protection modes
  141. Xof the input.
  142. X.TP
  143. X.B -P
  144. XLeave the output protection modes alone. This is the default.
  145. X.TP
  146. X.B -t
  147. XSet the access and modification times of the output to those
  148. Xof the input.
  149. X.TP
  150. X.B -T
  151. XLeave the times alone. This is the default.
  152. X.TP
  153. X\fB-o\fIout
  154. XWrite the output on file
  155. X\fIout\fB.
  156. XThis overrides
  157. Xthe 
  158. X.B\-e
  159. Xoption.
  160. X.TP
  161. X\fB-e\fIext
  162. XWrite the output on
  163. X\fIfile.ext\fB.
  164. X.PP
  165. XIf you specify neither
  166. X.B\-o
  167. Xnor
  168. X\fB\-e\fI,
  169. X\fIfilterfile\fB
  170. Xwill look for an environment variable
  171. X.B FILEFILTEREXT
  172. Xgiving an extension.
  173. XIf there is no such variable,
  174. X\fIfilterfile\fB
  175. Xwill give the output the same name as the input,
  176. Xfollowed by a period.
  177. X.PP
  178. XIf the extension begins with a period and the input file name
  179. Xends with that extension already, the extension is deleted from
  180. Xthe file name rather than added to it. If you really do want
  181. Xperiods in the extension, type them as slashes.
  182. X.PP
  183. XThe options and input file name can come in any order,
  184. Xbut the second argument not starting with a hyphen
  185. Xis taken to be the name of the filter.
  186. XAny further arguments are passed on as options to the filter.
  187. X.PP
  188. XYou need not specify a full path name for the filter.
  189. X.SH DIAGNOSTICS
  190. XAltogether too many,
  191. Xthough luckily most are self-explanatory.
  192. XMost of these messages are followed by a more specific explanation
  193. Xof the reason for the error; this list does not contain all the
  194. Xpossible variations.
  195. X.TP
  196. X\fIfatal: cannot create output file name: out of memory\fB
  197. XThere is so little memory available that
  198. X\fIfilterfile\fB
  199. Xcannot even put together the input file name and extension
  200. Xto make the output file name.
  201. X.TP
  202. X\fIfatal: will not proceed: input file has extra links\fB
  203. XYou have asked that the input file be deleted, but it
  204. Xhas more than one link.
  205. X.TP
  206. X\fIwarning: cannot change protections of output file\fB
  207. XThis should never happen,
  208. Xunless the file changes to someone else's ownership.
  209. X.TP
  210. X\fIfatal: cannot execute filter\fB
  211. X\fIfilterfile\fB
  212. Xis unable to execute the filter.
  213. X.TP
  214. X\fIfatal: cannot fork\fB
  215. XYou have probably run out of processes.
  216. X.TP
  217. X\fIfatal: cannot reopen input file\fB
  218. X\fIfilterfile\fB
  219. Xis unable to open the input file at its original location.
  220. X.TP
  221. X\fIfatal: cannot reopen output file\fB
  222. X\fIfilterfile\fB
  223. Xis unable to open the output file at its original location.
  224. X.PP
  225. XThe following errors should all be self-explanatory:
  226. X.TP
  227. X\fIfatal: cannot open input file\fB
  228. X.TP
  229. X\fIfatal: cannot create output file\fB
  230. X.TP
  231. X\fIfatal: will not delete input file: it has been moved\fB
  232. X.TP
  233. X\fIfatal: will not delete input file: it has extra links\fB
  234. X.TP
  235. X\fIfatal: cannot delete input file\fB
  236. X.TP
  237. X\fIwarning: will not set times of output file: it has been moved\fB
  238. X.TP
  239. X\fIwarning: cannot set times of output file\fB
  240. X.PP
  241. XThere are several errors that should never happen:
  242. X.TP
  243. X\fIfatal: cannot stat input file\fB
  244. X.TP
  245. X\fIfatal: cannot stat output file\fB
  246. X.TP
  247. X\fIfatal: cannot prepare input\fB
  248. X.TP
  249. X\fIfatal: cannot prepare output\fB
  250. X.TP
  251. X\fIfatal: can't find filter process\fB
  252. X.TP
  253. X\fIfatal: cannot restat input file\fB
  254. X.TP
  255. X\fIfatal: cannot restat output file\fB
  256. X.SH MACHINES
  257. X\fIfilterfile\fB
  258. Xhas been tested
  259. Xon an Astronautics ZS-2
  260. Xrunning ZSUnix.
  261. X.SH FILES
  262. XNone.
  263. X.SH BUGS
  264. XNone known.
  265. X.SH RESTRICTIONS
  266. X\fIfilterfile\fB
  267. Xtries its best to detect when a file has been moved,
  268. Xso that it won't delete the wrong file or change the times of
  269. Xthe wrong file. It also tries to detect when the input file
  270. Xhas several links, in which case it does not even try to delete
  271. Xthe file. Unfortunately, there is a very short period of time
  272. Xbetween these tests and the actual operations, so
  273. X\fIfilterfile\fB
  274. Xcould enter a (non-looping) race condition and act incorrectly.
  275. XThere is no way to avoid this race with available versions of UNIX.
  276. X.PP
  277. XIn other words, if you move the input file out of the way and give
  278. Xa different file the same name, the moment before
  279. X\fIfilterfile\fB
  280. Xremoves that filename,
  281. Xyou deserve what you get.
  282. X.SH VERSION
  283. Xfilterfile version 1.201, dated October 28, 1989.
  284. X.SH AUTHOR
  285. XCopyright 1989, Daniel J. Bernstein.
  286. X.SH "SEE ALSO"
  287. Xapply(1),
  288. Xxargs(1)
  289. END_OF_FILE
  290. if test 4968 -ne `wc -c <'filterfile.man'`; then
  291.     echo shar: \"'filterfile.man'\" unpacked with wrong size!
  292. fi
  293. # end of 'filterfile.man'
  294. fi
  295. if test -f 'filterfile.c' -a "${1}" != "-c" ; then 
  296.   echo shar: Will not clobber existing file \"'filterfile.c'\"
  297. else
  298. echo shar: Extracting \"'filterfile.c'\" \(9303 characters\)
  299. sed "s/^X//" >'filterfile.c' <<'END_OF_FILE'
  300. X/*
  301. Xfilterfile.c: Pipe a file through a filter into another file.
  302. X
  303. XThis program is an obnoxious example of how to check return codes.
  304. X*/
  305. X
  306. Xstatic char filterfileauthor[] =
  307. X"filterfile was written by Daniel J. Bernstein.\n\
  308. XInternet address: brnstnd@acf10.nyu.edu.\n";
  309. X
  310. Xstatic char filterfileversion[] = 
  311. X"filterfile version 1.201, October 28, 1989.\n\
  312. XCopyright (c) 1989, Daniel J. Bernstein.\n\
  313. XAll rights reserved.\n";
  314. X
  315. Xstatic char filterfilecopyright[] =
  316. X"filterfile version 1.201, October 28, 1989.\n\
  317. XCopyright (c) 1989, Daniel J. Bernstein.\n\
  318. XAll rights reserved.\n\
  319. X\n\
  320. XYou are granted the following rights: A. To make copies of this work in\n\
  321. Xoriginal form, so long as (1) the copies are exact and complete; (2) the\n\
  322. Xcopies include the copyright notice, this paragraph, and the disclaimer\n\
  323. Xof warranty in their entirety. B. To distribute this work, or copies made\n\
  324. Xunder the provisions above, so long as (1) this is the original work and\n\
  325. Xnot a derivative form; (2) you do not charge a fee for copying or for\n\
  326. Xdistribution; (3) you ensure that the distributed form includes the\n\
  327. Xcopyright notice, this paragraph, and the disclaimer of warranty in their\n\
  328. Xentirety. These rights are temporary and revocable upon written, oral, or\n\
  329. Xother notice by Daniel J. Bernstein. This copyright notice shall be\n\
  330. Xgoverned by the laws of the state of New York.\n\
  331. X\n\
  332. XIf you have questions about filterfile or about this copyright notice,\n\
  333. Xor if you would like additional rights beyond those granted above,\n\
  334. Xplease feel free to contact the author at brnstnd@acf10.nyu.edu\n\
  335. Xon the Internet.\n";
  336. X
  337. Xstatic char filterfilewarranty[] =
  338. X"To the extent permitted by applicable law, Daniel J. Bernstein disclaims\n\
  339. Xall warranties, explicit or implied, including but not limited to the\n\
  340. Ximplied warranties of merchantability and fitness for a particular purpose.\n\
  341. XDaniel J. Bernstein is not and shall not be liable for any damages,\n\
  342. Xincidental or consequential, arising from the use of this program, even\n\
  343. Xif you inform him of the possibility of such damages. This disclaimer\n\
  344. Xshall be governed by the laws of the state of New York.\n\
  345. X\n\
  346. XIn other words, use this program at your own risk.\n\
  347. X\n\
  348. XIf you have questions about filterfile or about this disclaimer of warranty,\n\
  349. Xplease feel free to contact the author at brnstnd@acf10.nyu.edu\n\
  350. Xon the Internet.\n";
  351. X
  352. Xstatic char filterfileusage[] =
  353. X"Usage: filterfile [ -dDpPtTACHUVW ] [ -oout ] [ -eext ]\n\
  354. X                  file /path/filter [ arg ... ]\n\
  355. XHelp:  filterfile -H\n";
  356. X
  357. Xstatic char filterfilehelp[] =
  358. X"filterfile applies a filter to a file, placing the output in a new file.\n\
  359. X\n\
  360. Xfilterfile -A: print authorship notice\n\
  361. Xfilterfile -C: print copyright notice\n\
  362. Xfilterfile -H: print this notice\n\
  363. Xfilterfile -U: print short usage summary\n\
  364. Xfilterfile -V: print version number\n\
  365. Xfilterfile -W: print disclaimer of warranty\n\
  366. X\n\
  367. Xfilterfile [ -dDpPtT ] [ -oout ] [ -eext ]\n\
  368. X           file /path/filter [ arg ... ]: apply filter to file\n\
  369. X  -d: delete input file\n\
  370. X  -D: do not delete input file (default)\n\
  371. X  -p: preserve protection of file\n\
  372. X  -P: do not preserve protection of file (default)\n\
  373. X  -t: preserve access and modification times of file\n\
  374. X  -T: do not preserve times (default)\n\
  375. X  -eext: sent output to file.ext, or if ext begins with . remove it from name\n\
  376. X  -oout: send output to out (overrides -e)\n\
  377. X\n\
  378. XIf you have questions about or suggestions for filterfile, please feel free\n\
  379. Xto contact the author, Daniel J. Bernstein, at brnstnd@acf10.nyu.edu\n\
  380. Xon the Internet.\n";
  381. X
  382. X#include <stdio.h>
  383. X#include <sys/types.h>
  384. X#include <sys/stat.h>
  385. X#include <sys/file.h>
  386. X#ifdef BSD
  387. X#include <limits.h>
  388. X#endif
  389. X#include <sys/wait.h>
  390. X#include <sys/time.h>
  391. X
  392. Xextern char *getenv(); 
  393. Xextern char *malloc(); 
  394. X
  395. Xint flagdelete = 0;
  396. Xint flagprotect = 0;
  397. Xint flagtimes = 0;
  398. X
  399. Xint flagunappend = 0;
  400. X
  401. Xchar *fnout = 0;
  402. Xchar *fnin = 0;
  403. Xchar **filter = 0;
  404. Xchar *fnappend = 0;
  405. X
  406. Xmain(argc,argv,envp)
  407. Xint argc;
  408. Xchar *argv[];
  409. Xchar *envp[];
  410. X{
  411. X char *s;
  412. X int f;
  413. X int fdin;
  414. X int fdout;
  415. X union wait wstat;
  416. X struct stat stinold;
  417. X struct stat stoutold;
  418. X struct stat stin;
  419. X struct stat stout;
  420. X struct timeval tvp[2];
  421. X
  422. X fnappend = getenv("FILTERFILEEXT");
  423. X
  424. X while (*(++argv))
  425. X   if (**argv == '-')
  426. X     while (*(++(*argv)))
  427. X       switch(**argv)
  428. X        {
  429. X     case 'd': flagdelete = 1; break;
  430. X     case 'D': flagdelete = 0; break;
  431. X     case 'p': flagprotect = 1; break;
  432. X     case 'P': flagprotect = 0; break;
  433. X     case 't': flagtimes = 1; break;
  434. X     case 'T': flagtimes = 0; break;
  435. X     case 'e': fnappend = *argv + 1;
  436. X           while (*(++(*argv))) /* null */ ;
  437. X           --(*argv); break; /* we really want breakbreak here */
  438. X     case 'o': fnout = *argv + 1;
  439. X           while (*(++(*argv))) /* null */ ;
  440. X           --(*argv); break; /* we really want breakbreak here */
  441. X     case 'A': printf(filterfileauthor); exit(0);
  442. X         case 'C': printf(filterfilecopyright); exit(0);
  443. X         case 'V': printf(filterfileversion); exit(0);
  444. X         case 'W': printf(filterfilewarranty); exit(0);
  445. X         case 'H': printf(filterfilehelp); exit(0);
  446. X         case 'U': printf(filterfileusage); exit(0);
  447. X         default: ;
  448. X    }
  449. X   else 
  450. X     if (fnin == 0) 
  451. X       fnin = *argv;
  452. X     else
  453. X       if (filter == 0) 
  454. X        {
  455. X         filter = argv;
  456. X     break;
  457. X        }
  458. X if ((fnin == 0) || (filter == 0))
  459. X  {
  460. X   printf(filterfileusage); exit(1);
  461. X  }
  462. X if (fnout == 0)
  463. X  {
  464. X   flagunappend = (*fnappend == '.');
  465. X   for (s = fnappend;*s;s++)
  466. X     if (*s == '/')
  467. X       *s = '.'; 
  468. X   fnout = malloc((unsigned) (strlen(fnin) + strlen(fnappend) + 2));
  469. X   if (fnout == 0)
  470. X    {
  471. X     fprintf(stderr,"filterfile: fatal: cannot create output file name: \
  472. Xout of memory\n");
  473. X     exit(1);
  474. X    }
  475. X   (void) strcpy(fnout,fnin);
  476. X   if (flagunappend && (strlen(fnout) > strlen(fnappend)) &&
  477. X    (strcmp(fnout + strlen(fnout) - strlen(fnappend),fnappend) == 0))
  478. X     fnout[strlen(fnout) - strlen(fnappend)] = 0;
  479. X   else
  480. X    {
  481. X     (void) strcat(fnout,".");
  482. X     if (fnappend != NULL)
  483. X       (void) strcat(fnout,fnappend);
  484. X    }
  485. X  }
  486. X
  487. X /* Okay. Now we have fnin, fnout, and filter. */
  488. X
  489. X fdin = open(fnin,O_RDONLY);
  490. X if (fdin == -1)
  491. X  { fprintf(stderr,"filterfile: fatal: cannot open input file ");
  492. X   perror(fnin); exit(1); }
  493. X if (fstat(fdin,&stinold) == -1)
  494. X  { perror("filterfile: fatal: cannot stat input file"); exit(1); }
  495. X if (flagdelete && (stinold.st_nlink > 1))
  496. X  { fprintf(stderr,"filterfile: fatal: will not proceed: \
  497. Xinput file %s has extra links\n",fnin); exit(1); }
  498. X
  499. X tvp[0].tv_sec = stinold.st_atime;
  500. X tvp[0].tv_usec = 0;
  501. X tvp[1].tv_sec = stinold.st_mtime;
  502. X tvp[1].tv_usec = 0;
  503. X
  504. X fdout = open(fnout,O_WRONLY | O_CREAT | O_EXCL,0600);
  505. X if (fdout == -1)
  506. X  { fprintf(stderr,"filterfile: fatal: cannot create output file ");
  507. X   perror(fnout); exit(1); }
  508. X if (fstat(fdout,&stoutold) == -1)
  509. X  { perror("filterfile: fatal: cannot stat output file"); exit(1); }
  510. X
  511. X if (flagprotect)
  512. X   if (fchmod(fdout,stinold.st_mode & 0777) == -1)
  513. X     perror("filterfile: warning: cannot change protections of output file");
  514. X
  515. X if ((f = fork()) == 0) /* child */
  516. X  {
  517. X   if (dup2(fdin,0) == -1)
  518. X    { perror("filterfile: fatal: cannot prepare input"); exit(1); }
  519. X   if (dup2(fdout,1) == -1)
  520. X    { perror("filterfile: fatal: cannot prepare output"); exit(1); }
  521. X   execvp(*filter,filter);
  522. X   fprintf(stderr,"filterfile: fatal: cannot execute filter\n");
  523. X   exit(1);
  524. X  }
  525. X else if (f == -1) /* fork failed */
  526. X  { perror("filterfile: fatal: cannot fork"); exit(1); }
  527. X
  528. X /* parent */
  529. X close(fdin);
  530. X close(fdout);
  531. X if (wait(&wstat) == -1) 
  532. X  { perror("filterfile: fatal: can't find filter process"); exit(1); }
  533. X if (wstat.w_T.w_Termsig)
  534. X   exit(1); 
  535. X if (wstat.w_T.w_Retcode)
  536. X   exit((int) wstat.w_T.w_Retcode); 
  537. X if (wstat.w_T.w_Coredump)
  538. X   exit(1); 
  539. X
  540. X /* Filter exited happily. */
  541. X
  542. X if (flagdelete)
  543. X  {
  544. X   /* Race! Race! Race! */
  545. X   fdin = open(fnin,O_RDONLY);
  546. X   if (fdin == -1)
  547. X    { fprintf(stderr,"filterfile: fatal: cannot reopen input file ");
  548. X     perror(fnin); exit(1); }
  549. X   if (fstat(fdin,&stin) == -1)
  550. X    { fprintf(stderr,"filterfile: fatal: cannot restat input file ");
  551. X     perror(fnin); exit(1); }
  552. X   if ((stin.st_dev != stinold.st_dev) || (stin.st_ino != stinold.st_ino))
  553. X    { fprintf(stderr,"filterfile: fatal: will not delete input file %s: \
  554. Xit has been moved\n",fnin); exit(1); }
  555. X   if (stin.st_nlink > 1)
  556. X    { fprintf(stderr,"filterfile: fatal: will not delete input file %s: \
  557. Xit has extra links\n",fnin); exit(1); }
  558. X   /* Race! Race! Race! */
  559. X   if (unlink(fnin) == -1)
  560. X    { fprintf(stderr,"filterfile: fatal: cannot delete input file ");
  561. X     perror(fnin); exit(1); }
  562. X   (void) close(fdin);
  563. X  }
  564. X
  565. X if (flagtimes)
  566. X  {
  567. X   /* Race! Race! Race! */
  568. X   fdout = open(fnout,O_RDONLY);
  569. X   if (fdout == -1)
  570. X    { fprintf(stderr,"filterfile: fatal: cannot reopen output file ");
  571. X     perror(fnout); exit(1); }
  572. X   if (fstat(fdout,&stout) == -1)
  573. X    { perror("filterfile: fatal: cannot restat output file"); exit(1); }
  574. X   if ((stout.st_dev != stoutold.st_dev) || (stout.st_ino != stoutold.st_ino))
  575. X    { fprintf(stderr,"filterfile: warning: will not set times of \
  576. Xoutput file %s: it has been moved\n",fnout); exit(1); }
  577. X   /* Race! Race! Race! */
  578. X   if (utimes(fnout,tvp) == -1)
  579. X    { fprintf(stderr,"filterfile: warning: cannot set times of output file ");
  580. X     perror(fnout); exit(1); }
  581. X  }
  582. X
  583. X exit(0);
  584. X}
  585. END_OF_FILE
  586. if test 9303 -ne `wc -c <'filterfile.c'`; then
  587.     echo shar: \"'filterfile.c'\" unpacked with wrong size!
  588. fi
  589. # end of 'filterfile.c'
  590. fi
  591. if test -f 'Makefile' -a "${1}" != "-c" ; then 
  592.   echo shar: Will not clobber existing file \"'Makefile'\"
  593. else
  594. echo shar: Extracting \"'Makefile'\" \(236 characters\)
  595. sed "s/^X//" >'Makefile' <<'END_OF_FILE'
  596. XCCOPTS=-O
  597. XNROFFOPTS=-man
  598. X
  599. Xdefault: all
  600. X
  601. Xall: filterfile filterfile.1
  602. X
  603. Xfilterfile: filterfile.c Makefile
  604. X    cc $(CCOPTS) -o filterfile filterfile.c
  605. X
  606. Xfilterfile.1: filterfile.man Makefile
  607. X    nroff $(NROFFOPTS) < filterfile.man > filterfile.1
  608. END_OF_FILE
  609. if test 236 -ne `wc -c <'Makefile'`; then
  610.     echo shar: \"'Makefile'\" unpacked with wrong size!
  611. fi
  612. # end of 'Makefile'
  613. fi
  614. echo shar: End of shell archive.
  615. exit 0
  616.  
  617.